import * as THREE from 'three';

// 建筑类型枚举
export enum BuildingType {
  HOUSE = 'house',
  SHOP = 'shop',
  FARMHOUSE = 'farmhouse'
}

// 建筑配置接口
export interface BuildingConfig {
  type: BuildingType;
  position: THREE.Vector3;
  rotation: number;
  scale: THREE.Vector3;
  color: number;
  hasWindows: boolean;
  windowColor: number;
}

// 道路点接口
export interface RoadPoint {
  position: THREE.Vector3;
  width: number;
  type: 'straight' | 'curve' | 'intersection';
}

// 村庄生成器类
export class VillageGenerator {
  private scene: THREE.Scene;
  private buildings: THREE.Group[] = [];
  private roads: THREE.Mesh[] = [];
  private ground: THREE.Mesh | null = null;
  private vegetation: THREE.Group[] = [];

  constructor(scene: THREE.Scene) {
    this.scene = scene;
  }

  // 生成完整村庄
  public generateVillage(): void {
    this.createGround();
    this.createRoadNetwork();
    this.generateBuildings();
    this.addVegetation();
  }

  // 创建地面
  private createGround(): void {
    const groundGeometry = new THREE.PlaneGeometry(100, 100);
    const groundMaterial = new THREE.MeshLambertMaterial({
      color: 0x2d5016,
      transparent: true,
      opacity: 0.9
    });

    this.ground = new THREE.Mesh(groundGeometry, groundMaterial);
    this.ground.rotation.x = -Math.PI / 2;
    this.ground.receiveShadow = true;
    this.scene.add(this.ground);

    // 添加地面纹理细节
    this.addGroundDetails();
  }

  // 添加地面细节
  private addGroundDetails(): void {
    const patchCount = 50;
    for (let i = 0; i < patchCount; i++) {
      const patchGeometry = new THREE.CircleGeometry(Math.random() * 2 + 0.5, 8);
      const patchMaterial = new THREE.MeshLambertMaterial({
        color: new THREE.Color().setHSL(0.25, 0.4, Math.random() * 0.3 + 0.2),
        transparent: true,
        opacity: 0.6
      });

      const patch = new THREE.Mesh(patchGeometry, patchMaterial);
      patch.position.set(
        (Math.random() - 0.5) * 90,
        0.01,
        (Math.random() - 0.5) * 90
      );
      patch.rotation.x = -Math.PI / 2;
      this.scene.add(patch);
    }
  }

  // 创建道路网络
  private createRoadNetwork(): void {
    // 主干道路径点
    const mainRoadPoints: THREE.Vector3[] = [
      new THREE.Vector3(-30, 0, -20),
      new THREE.Vector3(-10, 0, -20),
      new THREE.Vector3(0, 0, -10),
      new THREE.Vector3(10, 0, -5),
      new THREE.Vector3(25, 0, 0),
      new THREE.Vector3(30, 0, 15),
      new THREE.Vector3(20, 0, 25),
      new THREE.Vector3(0, 0, 30),
      new THREE.Vector3(-20, 0, 25),
      new THREE.Vector3(-30, 0, 10),
      new THREE.Vector3(-30, 0, -20)
    ];

    // 创建主干道
    this.createRoad(mainRoadPoints, 4);

    // 创建分支道路
    const branchRoads = [
      [new THREE.Vector3(-10, 0, -20), new THREE.Vector3(-15, 0, -30)],
      [new THREE.Vector3(0, 0, -10), new THREE.Vector3(5, 0, -25)],
      [new THREE.Vector3(25, 0, 0), new THREE.Vector3(35, 0, -5)],
      [new THREE.Vector3(20, 0, 25), new THREE.Vector3(25, 0, 35)],
      [new THREE.Vector3(-20, 0, 25), new THREE.Vector3(-30, 0, 30)]
    ];

    branchRoads.forEach(points => {
      this.createRoad(points, 2.5);
    });
  }

  // 创建道路
  private createRoad(points: THREE.Vector3[], width: number): void {
    const curve = new THREE.CatmullRomCurve3(points);
    const roadGeometry = new THREE.TubeGeometry(curve, 50, width / 2, 8, false);
    const roadMaterial = new THREE.MeshLambertMaterial({
      color: 0x333333,
      transparent: true,
      opacity: 0.9
    });

    const road = new THREE.Mesh(roadGeometry, roadMaterial);
    road.receiveShadow = true;
    this.scene.add(road);
    this.roads.push(road);

    // 添加路边线
    this.addRoadMarkings(curve, width);
  }

  // 添加道路标线
  private addRoadMarkings(curve: THREE.CatmullRomCurve3, width: number): void {
    const points = curve.getPoints(100);
    const lineGeometry = new THREE.BufferGeometry().setFromPoints(points);
    const lineMaterial = new THREE.LineBasicMaterial({
      color: 0xffff00,
      transparent: true,
      opacity: 0.6
    });

    const centerLine = new THREE.Line(lineGeometry, lineMaterial);
    centerLine.position.y = 0.01;
    this.scene.add(centerLine);
  }

  // 生成建筑物
  private generateBuildings(): void {
    const buildingConfigs: BuildingConfig[] = [
      // 住宅区
      {
        type: BuildingType.HOUSE,
        position: new THREE.Vector3(-25, 0, -15),
        rotation: 0,
        scale: new THREE.Vector3(1, 1, 1),
        color: 0x8B4513,
        hasWindows: true,
        windowColor: 0xffaa44
      },
      {
        type: BuildingType.HOUSE,
        position: new THREE.Vector3(-20, 0, -30),
        rotation: Math.PI / 4,
        scale: new THREE.Vector3(0.8, 1.2, 0.8),
        color: 0xA0522D,
        hasWindows: true,
        windowColor: 0xffaa44
      },
      {
        type: BuildingType.HOUSE,
        position: new THREE.Vector3(-35, 0, -5),
        rotation: -Math.PI / 6,
        scale: new THREE.Vector3(1.2, 0.9, 1.1),
        color: 0x654321,
        hasWindows: true,
        windowColor: 0xffaa44
      },

      // 商业区
      {
        type: BuildingType.SHOP,
        position: new THREE.Vector3(15, 0, -15),
        rotation: 0,
        scale: new THREE.Vector3(1.5, 1, 2),
        color: 0x696969,
        hasWindows: true,
        windowColor: 0x00ff88
      },
      {
        type: BuildingType.SHOP,
        position: new THREE.Vector3(35, 0, 10),
        rotation: Math.PI / 2,
        scale: new THREE.Vector3(1.3, 1.2, 1.8),
        color: 0x778899,
        hasWindows: true,
        windowColor: 0x88ffaa
      },

      // 农业区
      {
        type: BuildingType.FARMHOUSE,
        position: new THREE.Vector3(-25, 0, 35),
        rotation: 0,
        scale: new THREE.Vector3(2, 0.8, 1.5),
        color: 0x8B0000,
        hasWindows: true,
        windowColor: 0xffaa44
      },
      {
        type: BuildingType.FARMHOUSE,
        position: new THREE.Vector3(30, 0, 30),
        rotation: -Math.PI / 3,
        scale: new THREE.Vector3(1.8, 1, 2.2),
        color: 0x800000,
        hasWindows: true,
        windowColor: 0xffaa44
      },

      // 更多住宅
      {
        type: BuildingType.HOUSE,
        position: new THREE.Vector3(5, 0, 20),
        rotation: Math.PI / 6,
        scale: new THREE.Vector3(0.9, 1.3, 0.9),
        color: 0x9370DB,
        hasWindows: true,
        windowColor: 0xffaa44
      },
      {
        type: BuildingType.HOUSE,
        position: new THREE.Vector3(-15, 0, 15),
        rotation: -Math.PI / 4,
        scale: new THREE.Vector3(1.1, 1, 1.1),
        color: 0x4682B4,
        hasWindows: true,
        windowColor: 0xffaa44
      }
    ];

    buildingConfigs.forEach(config => {
      const building = this.createBuilding(config);
      this.buildings.push(building);
      this.scene.add(building);
    });
  }

  // 创建单个建筑物
  private createBuilding(config: BuildingConfig): THREE.Group {
    const buildingGroup = new THREE.Group();

    let mainGeometry: THREE.BoxGeometry;
    let geometryParams: { width: number; height: number; depth: number };
    
    switch (config.type) {
      case BuildingType.HOUSE:
        mainGeometry = new THREE.BoxGeometry(3, 3, 3);
        geometryParams = { width: 3, height: 3, depth: 3 };
        break;
      case BuildingType.SHOP:
        mainGeometry = new THREE.BoxGeometry(4, 4, 6);
        geometryParams = { width: 4, height: 4, depth: 6 };
        break;
      case BuildingType.FARMHOUSE:
        mainGeometry = new THREE.BoxGeometry(5, 2.5, 4);
        geometryParams = { width: 5, height: 2.5, depth: 4 };
        break;
    }

    const mainMaterial = new THREE.MeshLambertMaterial({
      color: config.color
    });

    const mainBuilding = new THREE.Mesh(mainGeometry, mainMaterial);
    mainBuilding.position.y = geometryParams.height / 2;
    mainBuilding.castShadow = true;
    mainBuilding.receiveShadow = true;
    buildingGroup.add(mainBuilding);

    // 添加屋顶
    const roof = this.createRoof(config.type, geometryParams);
    buildingGroup.add(roof);

    // 添加窗户
    if (config.hasWindows) {
      const windows = this.createWindows(config, geometryParams);
      windows.forEach(window => buildingGroup.add(window));
    }

    // 应用变换
    buildingGroup.position.copy(config.position);
    buildingGroup.rotation.y = config.rotation;
    buildingGroup.scale.copy(config.scale);

    return buildingGroup;
  }

  // 创建屋顶
  private createRoof(type: BuildingType, buildingParams: { width: number; height: number; depth: number }): THREE.Mesh {
    let roofGeometry: THREE.BufferGeometry;
    
    if (type === BuildingType.FARMHOUSE) {
      // 平屋顶
      roofGeometry = new THREE.BoxGeometry(
        buildingParams.width + 0.5,
        0.3,
        buildingParams.depth + 0.5
      );
    } else {
      // 三角屋顶
      roofGeometry = new THREE.ConeGeometry(
        Math.max(buildingParams.width, buildingParams.depth) * 0.7,
        2,
        4
      );
    }

    const roofMaterial = new THREE.MeshLambertMaterial({
      color: 0x8B0000
    });

    const roof = new THREE.Mesh(roofGeometry, roofMaterial);
    roof.position.y = buildingParams.height + 0.5;
    roof.castShadow = true;

    if (type !== BuildingType.FARMHOUSE) {
      roof.rotation.y = Math.PI / 4;
    }

    return roof;
  }

  // 创建窗户
  private createWindows(config: BuildingConfig, buildingParams: { width: number; height: number; depth: number }): THREE.Mesh[] {
    const windows: THREE.Mesh[] = [];
    const windowGeometry = new THREE.PlaneGeometry(0.8, 1);
    const windowMaterial = new THREE.MeshLambertMaterial({
      color: config.windowColor,
      emissive: config.windowColor,
      emissiveIntensity: 0.3,
      transparent: true,
      opacity: 0.8
    });

    // 前后窗户
    [-buildingParams.depth / 2 - 0.01, buildingParams.depth / 2 + 0.01].forEach((z, i) => {
      const window = new THREE.Mesh(windowGeometry, windowMaterial);
      window.position.set(0, buildingParams.height / 2, z);
      if (i === 1) window.rotation.y = Math.PI;
      windows.push(window);
    });

    // 左右窗户
    [-buildingParams.width / 2 - 0.01, buildingParams.width / 2 + 0.01].forEach((x, i) => {
      const window = new THREE.Mesh(windowGeometry, windowMaterial);
      window.position.set(x, buildingParams.height / 2, 0);
      window.rotation.y = i === 0 ? -Math.PI / 2 : Math.PI / 2;
      windows.push(window);
    });

    return windows;
  }

  // 添加植被
  private addVegetation(): void {
    // 添加树木
    this.addTrees();
    // 添加草丛
    this.addGrass();
  }

  // 添加树木
  private addTrees(): void {
    const treePositions = [
      new THREE.Vector3(-40, 0, -35),
      new THREE.Vector3(40, 0, -30),
      new THREE.Vector3(-45, 0, 20),
      new THREE.Vector3(35, 0, 40),
      new THREE.Vector3(-10, 0, 45),
      new THREE.Vector3(15, 0, -35),
      new THREE.Vector3(-35, 0, 40),
      new THREE.Vector3(45, 0, 15)
    ];

    treePositions.forEach(position => {
      const tree = this.createTree();
      tree.position.copy(position);
      this.vegetation.push(tree);
      this.scene.add(tree);
    });
  }

  // 创建单棵树
  private createTree(): THREE.Group {
    const treeGroup = new THREE.Group();

    // 树干
    const trunkGeometry = new THREE.CylinderGeometry(0.3, 0.5, 4);
    const trunkMaterial = new THREE.MeshLambertMaterial({ color: 0x8B4513 });
    const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
    trunk.position.y = 2;
    trunk.castShadow = true;
    treeGroup.add(trunk);

    // 树冠
    const crownGeometry = new THREE.SphereGeometry(3, 8, 6);
    const crownMaterial = new THREE.MeshLambertMaterial({ color: 0x228B22 });
    const crown = new THREE.Mesh(crownGeometry, crownMaterial);
    crown.position.y = 5;
    crown.castShadow = true;
    treeGroup.add(crown);

    return treeGroup;
  }

  // 添加草丛
  private addGrass(): void {
    const grassCount = 100;
    for (let i = 0; i < grassCount; i++) {
      const grass = this.createGrass();
      grass.position.set(
        (Math.random() - 0.5) * 80,
        0,
        (Math.random() - 0.5) * 80
      );
      
      // 避免在道路上生成草丛
      const distanceToCenter = grass.position.distanceTo(new THREE.Vector3(0, 0, 0));
      if (distanceToCenter > 8) {
        this.vegetation.push(grass);
        this.scene.add(grass);
      }
    }
  }

  // 创建草丛
  private createGrass(): THREE.Group {
    const grassGroup = new THREE.Group();
    const grassCount = Math.floor(Math.random() * 5) + 3;

    for (let i = 0; i < grassCount; i++) {
      const grassGeometry = new THREE.ConeGeometry(0.1, Math.random() * 0.8 + 0.5, 3);
      const grassMaterial = new THREE.MeshLambertMaterial({
        color: new THREE.Color().setHSL(0.25, 0.6, Math.random() * 0.3 + 0.3)
      });

      const grassBlade = new THREE.Mesh(grassGeometry, grassMaterial);
      grassBlade.position.set(
        (Math.random() - 0.5) * 0.5,
        grassGeometry.parameters.height / 2,
        (Math.random() - 0.5) * 0.5
      );
      grassBlade.rotation.z = (Math.random() - 0.5) * 0.3;
      grassGroup.add(grassBlade);
    }

    return grassGroup;
  }

  // 获取村庄建筑物（用于添加窗户灯光）
  public getBuildings(): THREE.Group[] {
    return this.buildings;
  }

  // 获取植被（用于碰撞检测）
  public getVegetation(): THREE.Group[] {
    return this.vegetation;
  }

  // 获取道路路径点（用于车辆AI路径）
  public getRoadPath(): THREE.Vector3[] {
    return [
      new THREE.Vector3(-30, 0.5, -20),
      new THREE.Vector3(-10, 0.5, -20),
      new THREE.Vector3(0, 0.5, -10),
      new THREE.Vector3(10, 0.5, -5),
      new THREE.Vector3(25, 0.5, 0),
      new THREE.Vector3(30, 0.5, 15),
      new THREE.Vector3(20, 0.5, 25),
      new THREE.Vector3(0, 0.5, 30),
      new THREE.Vector3(-20, 0.5, 25),
      new THREE.Vector3(-30, 0.5, 10)
    ];
  }

  // 清理资源
  public dispose(): void {
    [...this.buildings, ...this.vegetation].forEach(object => {
      this.scene.remove(object);
      object.traverse(child => {
        if (child instanceof THREE.Mesh) {
          child.geometry.dispose();
          if (Array.isArray(child.material)) {
            child.material.forEach(material => material.dispose());
          } else {
            child.material.dispose();
          }
        }
      });
    });

    this.roads.forEach(road => {
      this.scene.remove(road);
      road.geometry.dispose();
      if (Array.isArray(road.material)) {
        road.material.forEach(material => material.dispose());
      } else {
        road.material.dispose();
      }
    });

    if (this.ground) {
      this.scene.remove(this.ground);
      this.ground.geometry.dispose();
      if (Array.isArray(this.ground.material)) {
        this.ground.material.forEach(material => material.dispose());
      } else {
        this.ground.material.dispose();
      }
    }
  }
}